
///<reference path="../typings/tsd.d.ts" />
module AUTO {
    /**依赖日期 控件、zTree   目前假设ID是主键*/
    export class AutoForm {
        /**form本身，必须是form标签 */
        private $form: JQuery;
        /**form 内的table. */
        private $table: JQuery;
        /**保存和取消按钮 */
        private $btnSave: JQuery;
        private $btnCancle: JQuery;
        
        private keysList:string[]=[];
        private _opt: AutoFormOption = {
            action: "",
            ajaxurl: "",
            cols: 2,
            fields: [],
            tableName:"",
            values: []
        };
        /** 等待个数。因为有些是异步插入的，要等这些异步完成才行 */
        private waitCount = 0;
        constructor(element: Element, option: AutoFormOption) {
            this._opt = $.extend(this._opt, option);
            this.$form = $(element);
            this.init();
            this.renderTable();
            if (this._opt.values.length) {
                this.writeValues();
            }
            this.bindClickEvent();
        }
        public init() {
            this.$form.empty()
                .prop("action", this._opt.action)
                .addClass("autoForm")
                .append(`<table class='autoFormTable'></table>
                        <br>
        <div class="autoFormDiv">
            <button type="button" class="btn btn-warning btnCancel">
                <span class="glyphicon glyphicon-remove"></span> 取&nbsp;&nbsp;消
            </button>
            <button type="submit" class="btn btn-info btnSave">
                <span class="glyphicon glyphicon-ok"></span> 保&nbsp;&nbsp;存
            </button>
        </div>`);
            this.$table = this.$form.find(".autoFormTable");
            this.$btnSave = this.$form.find(".btnSave");
            this.$btnCancle = this.$form.find(".btnCancel");
        }
        /**根据字段，输出到form的table标签中去,之后绑定日期的功能 .
         * 如果类型是prikey,则添加到form，而不是添加到table中支 */
        public renderTable() {
            let scope = this;
            let content = "<tbody><tr>"; //输出到tbody中的内容
            let pos = 0;             //用来判断当前位置是否能容下一个字段
            _.each(this._opt.fields, function(item, idx) {
                if (item.type == "prikey")
                { 
                    scope.appendPrikey(item); 
                    return;
                }
                if ((pos + item.span) > scope._opt.cols) {
                    content += "</tr><tr>";
                    pos = item.span;
                } else {
                    pos += item.span;
                }
                let sndSpan = (item.span > 1) ? item.span * 2 - 1 : 1;
                content += `<td class="greyTD">${item.title}</td>`;
                content += `<td colspan="${sndSpan}">`;
                switch (item.type) {
                    case "string":
                        content += scope.renderString(item);
                        break;
                    case "number":
                        content += scope.renderNumber(item);
                        break;
                    case "select":
                        content += scope.renderSelect(item);
                        break;
                    case "tree":
                        content += scope.renderTree(item);
                        break;
                    case "date":
                        content += scope.renderDate(item);
                        break;
                    case "month":
                        content += scope.renderMonth(item);
                        break;
                    case "year":
                        content += scope.renderYear(item);
                        break;
                }
                content += `</td>`;
            });
            content += "</tr><tbody>";
            this.$table.append(content);
            //绑定日期 的方法
            this.$table.find('[data-type="date"]').datebox("nyr");
            this.$table.find('[data-type="month"]').datebox("ny");
            this.$table.find('[data-type="year"]').datebox("ny");
        }
        /**绑定一下取消和保存的事件*/
        public bindClickEvent() {
            let scope = this;
            this.$btnCancle.click(function() {
                //直接是触发用户事件
                scope._opt.canceled&&scope._opt.canceled();
            });
            this.$btnSave.click(function() {
                //这里插入窗体保存代码.
                scope.saveDate();
                if (scope._opt.action == "") {
                    return false;
                }
            });
        }
        public appendPrikey(item: AutoFormFieldsOptions) {
            this.$form.append(` <input name="${item.field}" type="hidden" value="">`);
            this.keysList.push(item.field);
        }
        private getPlaceholder(item:AutoFormFieldsOptions){
            return item.placeholder?`placeholder="${item.placeholder}"`:"";
        }
        public renderString(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="string" name="${item.field}"  ${this.getPlaceholder(item)}/>`;
        }
        public renderNumber(item: AutoFormFieldsOptions) {
            return `<input type="number" data-type="number" name="${item.field}"  ${this.getPlaceholder(item)}/>`;
        }
        private renderOptions(list: any[]) {
            let content = "";
            content += '<option value="">请选择</option>'
            _.each(list, function(item) {
                content += `<option value="${item["ID"]}">${item["MC"]}</option>;`
            });
            return content;
        }
        /**输出下拉选择， 有异步事件 */
        public renderSelect(item: AutoFormFieldsOptions) {
            let scope = this;
            let content = `<select data-type="select" name="${item.field}" >`;
            if (_.isString(item.addData)) {
                //插入一个等待
                scope.waitCount++;
                $.ajax(<string>item.addData, { type: 'GET', data: {}, dataType: 'json' })
                    .done(function(data) {
                        //异步写入下拉菜单
                        scope.$form.find(`[name=${item.field}]`).append(scope.renderOptions(<any[]>data));
                        scope.waitCount--;
                    });
            } else if (_.isArray(item.addData)) {
                content += scope.renderOptions(<any[]>item.addData);
            }
            content += '</select>';
            return content;
        }
        /**输出下拉树， 有异步事件 */
        public renderTree(item: AutoFormFieldsOptions) {
            let scope = this;
            let content = `<input type="hidden" data-type="tree" name="${item.field}" />`; //隐藏标签用于传id
            content += `<input type="text" data-type="tree" data-label="${item.field}"  ${this.getPlaceholder(item)}/>`;  //显示标签，用于显示名字
            //插入一个等待
            scope.waitCount++;
            content += (`<div class="formtree ztree"></div>`);
            //请求树数据,同时
            $.ajax(<string>item.addData, { type: 'GET', data: {}, dataType: 'json' })
                .done(function(treedata) {
                    let $input = scope.$form.find(`[name=${item.field}]`)
                        .data("treedata", treedata);
                    let $text = $input.next();
                    let $tree = $text.next();
                    //生成树
                    var setting = {
                        data: {
                            key: { name: "NAME" },
                            simpleData: { enable: true, idKey: "ID", pIdKey: "PID" }
                        },
                        callback: {
                            onDblClick: function(event, treeId, treeNode: TreeNode) {
                                if (treeNode && treeNode.ISLEAF == '1') {
                                    $input.val(treeNode.ID);
                                    $text.val(treeNode.NAME);
                                    $tree.hide();
                                }
                            }
                        }
                    };
                    $.fn.zTree.init($tree, setting, treedata);
                    //绑定点击文本时，显示树。  让父td  relative
                    $text.click(function() {
                        $tree.show();
                    });
                    $input.parent().css("position", "relative");
                    scope.waitCount--;
                });
            return content;
        }
        public renderDate(item: AutoFormFieldsOptions) {
            //日期列要增加_RQ的后缀，在后台处理过程中，会将其去掉。
            return `<input type="text" data-type="date" name="${item.field}_RQ" ${this.getPlaceholder(item)}/>`;
        }
        public renderMonth(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="month" name="${item.field}" ${this.getPlaceholder(item)}/>`;
        }
        public renderYear(item: AutoFormFieldsOptions) {
            return `<input type="text" data-type="year" name="${item.field}" ${this.getPlaceholder(item)}/>`;
        }
        /** 如果传入了formValues ,那么要将它写到表单中 */
        public writeValues() {
            let scope = this;
            //sql返回的对象一般是一个元素的数组，所以直接取0个元素
            if (scope._opt.values.length == 0) {
                return;
            }
            let row = scope._opt.values[0];
            if (this.waitCount > 0) {
                setTimeout(function() {
                    scope.writeValues();
                }, 500);
            } else {
                _.each(this._opt.fields, function(item, idx) {
                    let $input = scope.$form.find(`[name=${item.field}${item.type=="date"?"_RQ":""}]`);
                    let value = row[item.field];
                    //如果是树节点，则要找到其名称
                    if (item.type == "tree") {
                        let $text = $input.next();
                        let $tree = $text.next();
                        let treedata: TreeNode[] = $input.data("treedata");
                        let treenode = _.find(treedata, function(node) {
                            return node["ID"] == value;
                        });
                        $input.val(treenode.ID)
                        $text.val(treenode.NAME);
                    } else {
                        $input.val(value);
                    }
                });
            }
        }
        /**保存 如果是form提交，可能页面就切换了。
                如果ajax提交，才会走用户事件*/
        private saveDate() {
            let scope = this;
            if (this._opt.action == "") {
                let updata = this.$form.serializeArray();
                 updata.push({name:"_keys",value:this.keysList.join(",")});
                 updata.push({name:"_table",value:this._opt.tableName});
                 scope._opt.beforeSave&&scope._opt.beforeSave(updata);
                
                $.ajax(this._opt.ajaxurl, { type: 'POST', data: updata, dataType: 'json' })
                    .done(function() {
                        //触发用户的事件
                        scope._opt.saved&&scope._opt.saved();
                    });
            } else {
                (<HTMLFormElement>this.$form[0]).submit();
            }

        }
    }
}

$.fn["autoForm"] = function(option: AutoFormOption) {
    return this.each(function() {
        new AUTO.AutoForm(this, option);
    });
};